#include "Subdivider.h"

//==============================================================================
// Public Interface - public to all its subclasses
//==============================================================================

Subdivider::Subdivider()
{
	coarseVertexColor		= Vec4f( 0, 0.41, 1, 1 );
	connectedVertexColor	= Vec4f( 0.85, 0.87, 0.25, 1 );
	sharpEdgeColor			= Vec4f(  0.75, 0, 0.2, 1 );
}


/**
 *	This function will update the importance mesh's vertex positions based
 *  on the frame's active mesh.
 */
void Subdivider::updateImportanceMesh( ModelFrame* frame )
{
	if( frame->getImportanceMesh() && frame->active )
	{
		PolyMesh* imp = frame->getImportanceMesh();
		VIter vit(imp->vertices_begin()), vend(imp->vertices_end());
		Point p;

		for( ; vit!=vend; ++vit )
		{
			int index = imp->data( vit.handle() ).importance();
			p = frame->active->point( frame->active->vertex_handle(index) );
			imp->set_point( vit.handle(), p );
		}
	}
}


/**
 *	This function clears all sharp edges in the frame, resets vertex positions
 *  in subdivided mesh (to weighted values), and resets colors
 */
void Subdivider::clearSharpEdges( ModelFrame* frame )
{
	if( frame && frame->coarse && frame->subdivided )
	{
		EData ed, ed2;
		VData vd;
		EIter eit, eend;

		//reset all subdivided edges
		eit = frame->subdivided->edges_begin();
		eend = frame->subdivided->edges_end();
		for( ; eit != eend; ++eit )
		{
			ed = frame->subdivided->data( eit.handle() );
			ed2 = frame->reconnected->data( frame->reconnected->edge_handle((eit.handle()).idx()) );
			ed.set_sharp( false );
			ed2.setColor( this->connectedVertexColor );
			frame->subdivided->data( eit.handle()) = ed;
			frame->reconnected->data( frame->reconnected->edge_handle((eit.handle()).idx()) ) = ed2;

		}
		//reset all subdivided vertices
		VIter vit( frame->subdivided->vertices_begin() ), vend( frame->subdivided->vertices_end() );
		for( ; vit != vend; ++vit )
		{
			vd = frame->subdivided->data( vit.handle() );
			frame->subdivided->set_point( vit.handle(), vd.getPoint() );
		}

		//reset all colors in the connected mesh
		vit = frame->reconnected->vertices_begin();
		vend = frame->reconnected->vertices_end();
		for( ; vit != vend; ++vit )
			frame->reconnected->set_color( vit.handle(), connectedVertexColor );
		
		EHandle eh1, eh2;
		VData vd1;
		EData ed1;

		//reset all coarse edges and edge vertices colors
		eit = frame->coarse->edges_begin();
		eend = frame->coarse->edges_end();
		for( ; eit != eend; ++eit )
		{
			ed = frame->coarse->data( eit.handle() );
			ed.set_sharp( false );
			frame->coarse->data( eit.handle()) = ed;
			frame->reconnected->set_color( frame->reconnected->vertex_handle( ed.importance() ), connectedVertexColor );
			vd1 =  frame->subdivided->data( frame->subdivided->vertex_handle(ed.importance()) );
			eh1 = frame->subdivided->edge_handle( vd1.left_edge_index() );
			eh2 = frame->subdivided->edge_handle( vd1.right_edge_index() );

			//reset in connected mesh
			ed = frame->reconnected->data( frame->reconnected->edge_handle( eh1.idx() ) );
			ed1 = frame->reconnected->data( frame->reconnected->edge_handle( eh2.idx() ) );
			ed.setColor( this->coarseVertexColor );
			ed1.setColor( this->coarseVertexColor );
			frame->reconnected->data( frame->reconnected->edge_handle( eh1.idx() ) ) = ed;
			frame->reconnected->data( frame->reconnected->edge_handle( eh2.idx() ) ) = ed1;
		}
	}
}

//--------------------------------------------------------------------------------------------------
//  SUBDIVISION - HELPER FUNCTIONS (PROTECTED)
//--------------------------------------------------------------------------------------------------

/**
 *	This function prepares the internal meshes for subdividing...must call this before 
 *  calling "createMeshes()".  Also, this method clears up any unneeded memory by
 *  deleting the previous coarse mesh.
 */
void Subdivider::prepare( PolyMesh** coarse, PolyMesh** reconnected, PolyMesh** subdivided )
{
	/* remove coarse mesh and set previous subdivided mesh to be coarse mesh now */
	if( *subdivided && (*subdivided)->n_vertices() > 0 )
	{
		delete *coarse;
		*coarse = *subdivided;
	}
	*subdivided = new PolyMesh();
	subMesh = *subdivided;

	/* mesh = coarse mesh */
	mesh = *coarse;
	
	/* remove connectivity mesh, we don't need the old one anymore */
	if( *reconnected )
		delete *reconnected;
	*reconnected = new PolyMesh();
	connMesh = *reconnected;

	/* add custom, temporary properties to the vertices, edges and faces in the
	 * temp coarse mesh object -> to hold the handles of new vertex-vertices, face-vertices, and
	 * edge-vertices in the connected mesh and subdivided mesh */
	mesh->add_property( connV_V );
	mesh->add_property( subV_V );
	mesh->add_property( connE_V );
	mesh->add_property( subE_V );
	mesh->add_property( connF_V );
	mesh->add_property( subF_V );
}


/**
 *	This function removes all of the properties we added to the temporary coarse mesh, as weill
 *  as sets the reconnected and subdivided meshes to equal the newly calculated ones.  
 *  We also clear up all the memory we allocated to subdivide in here.
 */
void Subdivider::cleanup( PolyMesh** coarse, PolyMesh ** reconnected, PolyMesh** subdivided )
{
	/* remove all the custom mesh properties */
	mesh->remove_property( connV_V );
	mesh->remove_property( subV_V );
	mesh->remove_property( connE_V );
	mesh->remove_property( subE_V );
	mesh->remove_property( connF_V );
	mesh->remove_property( subF_V );

	/* make sure the new meshes have normals calculated */
	(*reconnected)->request_face_normals();
	(*subdivided)->request_face_normals();
	(*reconnected)->request_vertex_normals();
	(*subdivided)->request_vertex_normals();
	(*reconnected)->update_normals();
	(*subdivided)->update_normals();
}


/**
 *  This function calculates the even bspline mask for a given vertex, and returns the new
 *  position of the point (but doesn't set the point yet).  
 */
Point Subdivider::doVertexBoundary( PolyMesh*m, VHandle& vh, bool justBoundaries )
{
	VVIter vvIt;
	VHandle vh1, vh2;
	VData vd;
	EHandle eh;
	HHandle heh;
	bool found1 = false;

	for( vvIt = m->vv_iter( vh ); vvIt != false; ++vvIt )
	{
		vd = m->data( vvIt.handle() );
		heh = m->find_halfedge( vvIt.handle(), vh );
		eh = m->edge_handle( heh );

		/* find 1 adjacent boundary/sharp vertex */
		if( !found1&& ( (m->is_boundary( eh ) && m->is_boundary( vvIt.handle() )) || 
			(!justBoundaries && isSharp(m, vh, vvIt.handle()) ) ) )
		{
			vh1 = vvIt.handle();
			found1 = true;
		}
		/* find 2nd adjacent boundary/sharp vertex */
		else if( (m->is_boundary( eh ) && m->is_boundary( vvIt.handle() )) || 
			(!justBoundaries && isSharp(m, vh, vvIt.handle()) ) )
		{
			vh2 = vvIt.handle();
			break;
		}
	}
	/* new boundary vertex point is calculated using cubic bspline even mask */
	return (1.0/8.0) * m->point( vh1 ) + (3.0/4.0) * m->point( vh ) + (1.0/8.0) * m->point( vh2 );
}


//--------------------------------------------------------------------------------------------------
//  SHARP EDGE FUNCTIONS - Helper (Protected)
//--------------------------------------------------------------------------------------------------

/**
 *	This function finds the edge between two vertices and then returns true if this edge is sharp.
 */
bool Subdivider::isSharp(PolyMesh*m, VHandle& vh1, VHandle& vh2)
{
	EHandle eh;
	EData ed;
	//get halfedge connecting the two vertices
	HHandle heh = m->find_halfedge( vh1, vh2 );
	//get the edge connecting the two vertices
	eh = m->edge_handle( heh );
	//get the edge's data...to check it's sharpness member
	ed = m->data( eh );
	return ed.sharpness();
}


/**
 *	This function goes through all the edges in a coarse face.  If it encounters
 *  a sharp edge, it makes sure the corresponding edges in the subdivides mesh are set
 *  as sharp, too.  
 */
void Subdivider::setSharpnessInSubdivided( FHandle& fh )
{
	PolyMesh::FaceEdgeIter feIt( mesh->fe_iter(fh) );
	HHandle heh;
	VHandle vh1, vh2, vhedge, vhsub1, vhsub2;
	VData vd1, vd2, vdedge;
	EHandle ledge, redge;
	EData ed, led, red;
	bool isSharp;

	for(; feIt != false; ++feIt )
	{
		heh = mesh->halfedge_handle(feIt.handle(), 0);
		vh1 = mesh->from_vertex_handle( heh );
		vh2 = mesh->to_vertex_handle( heh );
		
		//get v_v's in subdivided mesh corresponding to the coarse ones
		vhsub1 = mesh->property( subV_V, vh1 );
		vhsub2 = mesh->property( subV_V, vh2 );

		//get edge vertex in subdivided mesh
		ed = mesh->data( feIt.handle() );
		vhedge = subMesh->vertex_handle( ed.importance() ); 

		//now, get the edges between the midpoint and outer vertices
		HHandle heh1, heh2;
		heh1 = subMesh->find_halfedge( vhsub1, vhedge );
		heh2 = subMesh->find_halfedge( vhsub2, vhedge );

		ledge = subMesh->edge_handle( heh1 );
		redge = subMesh->edge_handle( heh2 );

		//and set the right and left members of the vertex to equal these edge indices
		vdedge = subMesh->data( vhedge );
		vdedge.left_edge_index( ledge.idx() );
		vdedge.right_edge_index( redge.idx() );
		subMesh->data( vhedge ) = vdedge;
		//and do the same for the connected mesh, used for rendering		
		vdedge = connMesh->data( connMesh->vertex_handle(vhedge.idx()) );
		vdedge.left_edge_index( ledge.idx() );
		vdedge.right_edge_index( redge.idx() );
		connMesh->data( connMesh->vertex_handle(vhedge.idx()) ) = vdedge;

		//if coarse edge was sharp, set the subdivided edges from it to be sharp too
		led = subMesh->data( ledge );
		red = subMesh->data( redge );
		bool sharp = ed.sharpness();
		led.set_sharp(sharp);
		red.set_sharp(sharp);
		subMesh->data( ledge ) = led;
		subMesh->data( redge ) = red;
			
		led = connMesh->data( connMesh->edge_handle(ledge.idx()) );
		red = connMesh->data( connMesh->edge_handle(redge.idx()) );
		if( sharp ) //change the colors for rendering the sharp edges differently
		{
			led.setColor( sharpEdgeColor );
			red.setColor( sharpEdgeColor );
			connMesh->set_color( connMesh->vertex_handle(vhsub1.idx()), sharpEdgeColor );
			connMesh->set_color( connMesh->vertex_handle(vhsub2.idx()), sharpEdgeColor );
			connMesh->set_color( connMesh->vertex_handle(vhedge.idx()), sharpEdgeColor );
			mesh->set_color( mesh->vertex_handle(vh1.idx()), sharpEdgeColor );
			mesh->set_color( mesh->vertex_handle(vh2.idx()), sharpEdgeColor );
		}
		else
		{
			led.setColor( coarseVertexColor );
			red.setColor( coarseVertexColor );
		}
		connMesh->data( connMesh->edge_handle(ledge.idx()) ) = led;
		connMesh->data( connMesh->edge_handle(redge.idx()) ) = red;
	}
}


/**
 *	This function checks to see whether the specified vertex is sharp and returns its
 *  sharpness.  The different values of sharpness are:
 *
 *  COARSE - if the vertex has 2 sharp edges attached to it
 *  CORNER - if the vertex has more than 2 sharp edges attached to it
 *  NO_SHARPNESS - if less than 2 sharp edges are attached
 */
Sharpness Subdivider::isSharp( PolyMesh* m, VHandle& vh )
{
	PolyMesh::VertexEdgeIter veIt(m->ve_iter(vh));
	EData ed;
	VData vd;
	EHandle eh;
	int count = 0;

	//go through all attached edges for the vertex
	for( ; veIt != false; ++veIt )
	{
		ed = m->data( veIt.handle() );
		//has a sharp edge attached
		if( ed.sharpness() )
			count++;

		if( count > 2 )
			return CORNER;
	}
	if( count==2 )
		return CREASE;
	if( count==1 && m->is_boundary( vh ) )
		return ONE_EDGE_BOUNDARY;
	if( count==1 )
		return ONE_EDGE;

	return NO_SHARPNESS;
}


void Subdivider::clearWeights(PolyMesh* m, PolyMesh* im)
{
	PolyMesh::VertexIter vIt;
	Vec4f color = Vec4f(  0.75, 0, 0.2, 1 );

	if( im )
	{
		im->clear();
	}
	for(vIt = m->vertices_begin(); vIt != m->vertices_end(); ++vIt)
	{
		if( m->color( vIt.handle() ) == color )
		{
			VData vd = m->data( vIt.handle() );
			m->set_color( vIt.handle(), vd.getColor() );
		}

		m->data(vIt.handle()).set_weight(0);
	}
}

